package marvin.webapp.shopping.xml;

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import marvin.webapp.exception.MarvinException;
import marvin.webapp.shopping.model.Item;
import marvin.webapp.shopping.model.ShoppingList;

public class ShoppingListXMLParser {
	public static ShoppingList parse(File xmlFile) throws MarvinException {
		ShoppingList list = new ShoppingList();

		DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
				.newInstance();
		DocumentBuilder docBuilder;
		try {
			docBuilder = docBuilderFactory.newDocumentBuilder();

			Document doc = docBuilder.parse(xmlFile);

			// normalize text representation
			doc.getDocumentElement().normalize();

			NodeList shoopingListNodes = doc.getElementsByTagName(ShoppingListXMLWriter.ROOT_NODE_NAME);
			
			// if there is no element or more than one, that means that the provided file is not correct
			if(shoopingListNodes == null || shoopingListNodes.getLength() != 1){
				throw new MarvinException("Invalid XML file provided for parsing");
			}
			
			for (int index = 0 ; index < shoopingListNodes.getLength(); index++) {
				Node rootNode = shoopingListNodes.item(index);
				// creation date
				Node createdAtAtt = rootNode.getAttributes().getNamedItem(ShoppingListXMLWriter.CREATED_AT_ATTRIBUTE_NAME);
				if(createdAtAtt != null)
					list.setCreationDate(createdAtAtt.getTextContent());
				
				if(rootNode.getNodeType() == Node.ELEMENT_NODE){
                    Element rootNodeElement = (Element)rootNode;
                    NodeList itemsNodes = rootNodeElement.getElementsByTagName(ShoppingListXMLWriter.ITEMS_NODE_NAME);
                    buildItems(list, itemsNodes);
				}
				
			}
			
		} catch (ParserConfigurationException e) {
			throw new MarvinException(
					"An error has occured during XML parsing", e);
		} catch (SAXException e) {
			throw new MarvinException(
					"An error has occured during XML parsing", e);
		} catch (IOException e) {
			throw new MarvinException(
					"An error has occured during XML parsing", e);
		}
		return list;
	}
	
	private static void buildItems(ShoppingList shoppingList, NodeList itemsNodes) {
		for (int index = 0 ; index < itemsNodes.getLength(); index++) {
			Node rootNode = itemsNodes.item(index);
			if(rootNode.getNodeType() == Node.ELEMENT_NODE){
                Element rootNodeElement = (Element)rootNode;
                NodeList itemsListNode = rootNodeElement.getElementsByTagName(ShoppingListXMLWriter.ITEM_NODE_NAME);
                buildItemsList(shoppingList, itemsListNode);
			}
		}
	}
	
	private static void buildItemsList(ShoppingList shoppingList, NodeList itemsListNode) {
		for (int index = 0 ; index < itemsListNode.getLength(); index++) {
			Item item = new Item();
			Node itemNode = itemsListNode.item(index);
			// item name
			Node nameAtt = itemNode.getAttributes().getNamedItem(ShoppingListXMLWriter.NAME_ATTRIBUTE_NAME);
			if(nameAtt != null)
				item.setName(nameAtt.getTextContent());
			// item quantity 
			Node quantityAtt = itemNode.getAttributes().getNamedItem(ShoppingListXMLWriter.QUANTITY_ATTRIBUTE_NAME);
			if(quantityAtt != null)
				item.setQuantity(Integer.parseInt(quantityAtt.getTextContent()));
			
			// item is ticked
			Node tickedAtt = itemNode.getAttributes().getNamedItem(ShoppingListXMLWriter.TICKED_ATTRIBUTE_NAME);
			if(tickedAtt != null)
				item.setTicked(Boolean.valueOf(tickedAtt.getTextContent()));

			shoppingList.addItem(item);
		}
	}

	public static void main(String argv[]) {
		try {
			ShoppingListXMLParser.parse(new File("dummyList.xml"));
		} catch (MarvinException e) {
			e.printStackTrace();
		}
	}
}
